<?php
declare(strict_types = 1);
namespace Haozing\FastCore\Command;
use Hyperf\Command\Annotation\Command;
use Hyperf\Stringable\Str;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Throwable;

#[Command]
class PluginCommand extends CoreCommand
{

    protected ?string $name = 'hei:create';
    protected ?string $type = '';
    protected ?string $moduleAppName = '';
    protected ?string $moduleName = '';
    protected ?string $moduleDesc = '';
    protected ?string $moduleVersion = '';
    protected ?string $moduleAuthor = '';
    public function configure(): void
    {
        parent::configure();
        $this->setHelp('run "php bin/hyperf.php hei:create" create the new plugin');
        $this->setDescription('heiAdmin system gen plugin command');
        $this->addOption('install','i', InputOption::VALUE_NONE, '是否安装插件？');
    }
    /**
     * @throws Throwable
     */
    public function handle(): void
    {
        //通过提示语让用户输入参数,从参数中判断是创建插件还是应用的模块，为方便用户输入使用0为插件，1为应用表示。
        $this->output->writeLn($this->getGreenText('Start creating module...'));
        $type = $this->ask('Please choose to create an application module or a plugin?[1: Module, 2: Plugin],default:','1');
        //获取ask输入的参数
        if ($type == 1) {
            $this->type = 'module';
        } else {
            $this->type = 'plugin';
        }
        //如果是module那么需要让用户输入app的名字，否则只需要输入模块名字
        if ($this->type == 'module') {
            $this->output->writeLn($this->getGreenText('Start creating module...'));
            $appName = $this->ask('Please enter the application name.[For example: shop]','shop');
            if (empty($appName)) {
                $this->output->writeLn($this->getRedText('Please enter the application name'));
                return;
            }
            //应用的名字只能包含字母、数字、横杠,否则提示用户输入正确
            if (!preg_match("/^[a-z0-9](-?[a-z0-9]+)*$/", $appName)) {
                $this->output->writeLn($this->getRedText('Application name format error:Can only contain [letters, numbers, _, -]'));
                return;
            }
            $this->moduleAppName = $appName;
        }
        //获取用户创建module的名字
        $pluginName = $this->ask('Please enter the module name.[For example: user]','user');
        //判断用户输入的module名字是否为空
        if (empty($pluginName)) {
            $this->output->writeLn($this->getRedText('Please enter the module name'));
            return;
        }
        if (!preg_match("/^[a-z0-9](-?[a-z0-9]+)*$/", $pluginName)) {
            $this->output->writeLn($this->getRedText('Module name format error:Can only contain [letters, numbers, _, -]'));
            return;
        }
        $this->moduleName = $pluginName;
        //获取用户输入的模块介绍，可选项
        $this->moduleDesc = $this->ask('Please enter the module description.',$this->moduleName);

        $this->moduleAuthor = $this->ask('Please enter the module author.','admin');

        $this->moduleVersion = $this->ask('Please enter the module version.','1.0.0');

        //设置模块的根目录
        $srcName = "";
        if ($this->type == 'module') {
            $srcName = "apps".DIRECTORY_SEPARATOR.$this->moduleAppName.DIRECTORY_SEPARATOR.$pluginName;
        } else {
            $srcName = "plugins".DIRECTORY_SEPARATOR.$this->moduleName;
        }
        //判断目录是否存在，如果存在就提示用户该模块已经存在，否则就创建该模块
        if (file_exists($srcName)) {
            $this->output->writeLn($this->getRedText('The module already exists'));
            return;
        }
        $this->output->writeLn($this->getGreenText('Start creating module...'));
        //创建模块的目录
        $basePath = BASE_PATH . DIRECTORY_SEPARATOR  . $srcName;
        // 默认生成目录
        $pathNames = [
            "src",
            "publish",
            "manifest",
            "tests",
            "tests".DIRECTORY_SEPARATOR."Cases",
            "src".DIRECTORY_SEPARATOR."Constants",
            "src".DIRECTORY_SEPARATOR."Controller",
            "src".DIRECTORY_SEPARATOR."Database",
            "src".DIRECTORY_SEPARATOR."Database".DIRECTORY_SEPARATOR."Migrations",
            "src".DIRECTORY_SEPARATOR."Database".DIRECTORY_SEPARATOR."Migrations".DIRECTORY_SEPARATOR."Update",
            "src".DIRECTORY_SEPARATOR."Database".DIRECTORY_SEPARATOR."Seeders",
            "src".DIRECTORY_SEPARATOR."Exception",
            "src".DIRECTORY_SEPARATOR."Listener",
            "src".DIRECTORY_SEPARATOR."Process",
            "src".DIRECTORY_SEPARATOR."Open",
            "src".DIRECTORY_SEPARATOR."Open".DIRECTORY_SEPARATOR."Api",
            "src".DIRECTORY_SEPARATOR."Open".DIRECTORY_SEPARATOR."Interface",
            "src".DIRECTORY_SEPARATOR."Open".DIRECTORY_SEPARATOR."Event",
            "src".DIRECTORY_SEPARATOR."Open".DIRECTORY_SEPARATOR."Mock",
            "src".DIRECTORY_SEPARATOR."Logic",
            "src".DIRECTORY_SEPARATOR."Service".DIRECTORY_SEPARATOR."Model",
        ];
        //根据插件名称生成目录
        foreach ($pathNames as $pathName) {
            $path = $basePath . DIRECTORY_SEPARATOR  . $pathName;
            if (!file_exists($path)) {
                mkdir($path, 0777, true);
            }
        }
        //生成配置文件等等
        $classToFile = [
            "composer.json" => "composer.stub",
            "ppinfo.json" => "ppinfo.stub",
            ".gitignore" => "gitignore.stub",
            ".php-cs-fixer" => "php-cs-fixer.stub",
            "phpunit" => "phpunit.stub",
            "publish".DIRECTORY_SEPARATOR."config.php" => "config.stub",
            "tests".DIRECTORY_SEPARATOR."bootstrap.php" => "bootstrap.stub",
            "tests".DIRECTORY_SEPARATOR."Cases".DIRECTORY_SEPARATOR."AbstractTestCase.php" => "abstractTestCase.stub",
            "tests".DIRECTORY_SEPARATOR."Cases".DIRECTORY_SEPARATOR."ExampleTest.php" => "exampleTest.stub",
            //ConfigProvider.php
            "src".DIRECTORY_SEPARATOR."ConfigProvider.php" => "configProvider.stub",
        ];
        $ModuleAppName = Str::lower($this->moduleAppName);
        $ModuleName = Str::lower($this->moduleName);
        $ModuleDesc = $this->moduleDesc;
        $ModuleAuthor = $this->moduleAuthor;
        $ModuleVersion = $this->moduleVersion;

        //如果插件类型是module，那么ModuleComposerName就是'app/$ModuleAppName.$ModuleName'
        if ($this->type == 'module') {
            $ModuleComposerName = 'apps/'.$ModuleAppName.'.'.$ModuleName;
            $ModulePsrName = 'Apps\\\\'.Str::studly($ModuleAppName).'\\\\'.Str::studly($ModuleName);
            $ModuleNamespaceName = 'Apps\\'.Str::studly($ModuleAppName).'\\'.Str::studly($ModuleName);
        }else{
            $ModuleComposerName = 'plugins/'.$ModuleName;
            $ModulePsrName = 'Plugins\\\\'.Str::studly($ModuleName);
            $ModuleNamespaceName = 'Plugins\\'.Str::studly($ModuleName);
        }
        //生成文件
        foreach ($classToFile as $class => $file) {
            $stub = __DIR__ .DIRECTORY_SEPARATOR. 'stubs'. DIRECTORY_SEPARATOR .'plugin'. DIRECTORY_SEPARATOR . $file;
            $stub = file_get_contents($stub);
            //替换占位符
            $fileContent = str_replace(
                ['%ModuleComposerName%', '%ModulePsrName%','%ModuleNamespaceName%','%ModuleAppName%','%ModuleName%','%ModuleDesc%','%ModuleAuthor%','%ModuleVersion%'],
                [$ModuleComposerName, $ModulePsrName,$ModuleNamespaceName ,$ModuleAppName,$ModuleName,$ModuleDesc,$ModuleAuthor,$ModuleVersion],
                $stub
            );
            file_put_contents($basePath.DIRECTORY_SEPARATOR.$class, $fileContent);
        }
        $this->output->writeLn($this->getGreenText('plugin create success!'));
        //查看命令行是否有-i参数
        if ($this->input->getOption('install')) {
            $this->output->writeLn($this->getGreenText('Start installing plugin...'));
            // 执行composer require 插件
            $this->output->writeLn($this->getGreenText('composer install...'));
            $se = shell_exec('composer require '.$ModuleComposerName.':*');
            if ($se) {
                $this->output->writeLn($this->getRedText('composer install error!'));
                $this->output->writeLn($this->getRedText($se));
                return;
            }
            $this->output->writeLn($this->getGreenText('composer install success!'));
        }
    }
    protected function getArguments(): array
    {
        return [
            ['name', InputArgument::OPTIONAL, '插件名称'],
            ['order', InputArgument::OPTIONAL, '插件权重'],
            ['code', InputArgument::OPTIONAL, '插件错误码'],
        ];
    }

    protected function mkdir(string $path): void
    {
        $dir = dirname($path);
        if (! is_dir($dir)) {
            @mkdir($dir, 0755, true);
        }
    }
}